package de.mpii.html.parser;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.mpii.struct.tree.Tree;
import de.mpii.struct.tree.TreeNode;

public class HtmlParser extends Parser {

	private final String tagBegin;
	private final String tagEnd;
	private boolean allowNested;

	private Tree<String> parseTree;

	private List<TreeNode<String>> leaves;
	private int iterator;
	protected final Map<String, Object> properties = new HashMap<String, Object>();

	public HtmlParser(String tagBegin, String tagEnd, boolean allowNested) {
		this.tagBegin = tagBegin;
		this.tagEnd = tagEnd;
		this.allowNested = allowNested;
	}

	@Override
	public String next() {

		if (allowNested) {

			if (parseTree == null) {
				parseTree = parse();
				leaves = parseTree.getLeaves();
				iterator = 0;

				System.out.println(">> THE TREE \n" + parseTree);
			}

			if (leaves.isEmpty() || leaves.get(0).isRoot()
					|| iterator == leaves.size())
				return null;

			return leaves.get(iterator++).getObject();

		} else
			return nextSequencial();
	}

	private String nextSequencial() {
		String value;

		int posb2;

		posb = content.indexOf(tagBegin, pose);
		if (posb == -1)
			return null;

		posb2 = content.indexOf(">", posb);
		if (posb2 == -1)
			return null;

		if (posb2 > posb + tagBegin.length()) {
			String propertyString = content.substring(posb + tagBegin.length(),
					posb2);

			processProperties(propertyString.trim());
		}

		pose = content.indexOf(tagEnd, posb);
		if (pose == -1)
			return null;

		value = content.substring(posb2 + 1, pose);

		return value;
	}

	private Tree<String> parse() {
		Tree<String> tree = new Tree<String>();

		int start, end = 0;
		start = content.indexOf(tagBegin, end);

		if (start == -1)
			return tree;

		TreeNode<String> root = tree.getRoot();
		TreeNode<String> child;

		while (start != -1) {
			child = new TreeNode<String>();
			root.add(child);

			end = parse(child, start);

			if (end == -1) {
				System.out.println(">> STATUS: MAL-FORMATED 0.1.");
				break;
			}

			child.setObject(content.substring(start, end + tagEnd.length()));

			start = content.indexOf(tagBegin, end);
		}

		return tree;
	}

	/**
	 * 
	 * @param self
	 * @param start
	 * @return return posEnd, the end boundary of the coverage of self
	 */
	private int parse(TreeNode<String> self, int start) {
		assert start != -1;

		int nextStart, nextEnd;

		nextStart = content.indexOf(tagBegin, start + 1);
		nextEnd = content.indexOf(tagEnd, start);

		boolean hasNextStart, hasNextEnd;

		hasNextStart = nextStart != -1;
		hasNextEnd = nextEnd != -1;

		if (!hasNextStart && !hasNextEnd) {
			// mal-formated
			System.out.println(">> STATUS: MAL-FORMATED 1.1.");
			return -1;
		}

		if (hasNextStart && !hasNextEnd) {
			// mal-formated
			System.out.println(">> STATUS: MAL-FORMATED 1.2.");
			return -1;
		}

		if (!hasNextStart && hasNextEnd) {
			// should wrap up, .
			System.out.println(">> STATUS: WRAP UP 1.");
			return nextEnd;
		}

		assert hasNextStart && hasNextEnd;

		if (nextStart > nextEnd) {
			// aligned
			System.out.println(">> STATUS: ALIGNED 1.");
			return nextEnd;
		} else {
			// nested
			System.out.println(">> STATUS: NESTED.");

			TreeNode<String> child = new TreeNode<String>();
			self.add(child);

			int end = parse(child, nextStart);

			if (end == -1) {
				System.out.println(">> STATUS: MAL-FORMATED 1.3.");
				return -1;
			}

			child.setObject(content.substring(nextStart, end + tagEnd.length()));

			while (end != -1) {
				nextStart = content.indexOf(tagBegin, end);
				nextEnd = content.indexOf(tagEnd, end + 1);

				hasNextStart = nextStart != -1;
				hasNextEnd = nextEnd != -1;

				if (!hasNextStart && !hasNextEnd) {
					System.out.println(">> STATUS: MAL-FORMATED 2.1.");
					return -1;
				}

				if (hasNextStart && !hasNextEnd) {
					// mal-formated
					System.out.println(">> STATUS: MAL-FORMATED 2.2.");
					return -1;
				}

				if (!hasNextStart && hasNextEnd) {
					// should wrap up, .
					System.out.println(">> STATUS: WRAP UP 2.");
					return nextEnd;
				}

				assert hasNextStart && hasNextEnd;

				if (nextStart > nextEnd) {
					// aligned
					System.out.println(">> STATUS: ALIGNED 2.");
					return nextEnd;
				} else {

					child = new TreeNode<String>();
					self.add(child);

					end = parse(child, nextStart);

					if (end == -1) {
						System.out.println(">> STATUS: MAL-FORMATED 2.3.");
						return -1;
					}

					child.setObject(content.substring(nextStart,
							end + tagEnd.length()));
				}
			}

			System.out.println(">> STATUS: MAL-FORMATED 1.4.");
			return -1;
		}

	}

	private void processProperties(String string) {
		if (string.isEmpty())
			return;

		String[] segs = string.split("\\s+");

		for (String seg : segs) {
			String[] values = seg.split("=");

			if (values.length != 2)
				continue;

			properties.put(values[0], values[1]);
		}

		// System.out.println(">> PROPERTY " + properties);
	}

	@Override
	public void reset() {
		super.reset();
		iterator = 0;
	}

}
